package com.bytz.modules.cms.domain.impl.pay;

import cn.hutool.core.lang.Assert;
import com.bytz.common.exception.BytzBootException;
import com.bytz.modules.cms.common.service.CmsConfigService;
import com.bytz.modules.cms.domain.model.pay.BalancePayIn;
import com.bytz.modules.cms.domain.model.pay.BalancePayItem;
import com.bytz.modules.cms.domain.model.pay.BalancePayPrepareContext;
import com.bytz.modules.cms.domain.util.PriceComputerUtil;
import com.bytz.modules.cms.order.constant.OrderConstants;
import com.bytz.modules.cms.order.constant.OrderPayConstants;
import com.bytz.modules.cms.order.entity.*;
import com.bytz.modules.cms.order.model.PayNotifyResult;
import com.bytz.modules.cms.order.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class BalancePayProcessor extends AbstractPayProcessor<BalancePayIn, BalancePayPrepareContext> {

    private IOrderPickUpDetailService pickUpDetailService;

    @Autowired
    public BalancePayProcessor(IOrderService orderService,
                               IOrderItemService orderItemService,
                               IOrderPayService orderPayService,
                               IOrderPayDetailService orderPayDetailService,
                               IOrderOfflinePayService orderOfflinePayService,
                               IOrderPickUpDetailService pickUpDetailService,
                               IOrderEmailService orderEmailService,
                               CmsConfigService configService) {
        super(orderService, orderItemService, orderPayService, orderPayDetailService, orderOfflinePayService, orderEmailService, configService);

        this.pickUpDetailService = pickUpDetailService;
    }

    @Override
    protected BalancePayPrepareContext createPrepareContext() {
        return new BalancePayPrepareContext();
    }

    @Override
    protected void setOrderPayCustomProperties(OrderPay orderPay, BalancePayIn balancePayIn) {
        orderPay.setShipToAddress(balancePayIn.getShipToAddress());
        orderPay.setShipToContact(balancePayIn.getShipToContact());
        orderPay.setShipToName(balancePayIn.getShipToName());
        orderPay.setShipToNumber(balancePayIn.getShipToNumber());
        orderPay.setShipToPhone(balancePayIn.getShipToPhone());
    }

    @Override
    protected List<String> getCanPayOrderStatus() {
        return OrderConstants.OrderStatus.CAN_BALANCE_PAY_STATUS;
    }

    @Override
    public void calculatePayAmount(BalancePayIn payIn, BalancePayPrepareContext context) {
        List<OrderItem> orderItems = context.getOrderItems();
        BigDecimal totalPay = BigDecimal.ZERO;
        Map<String, OrderItem> orderItemMap = orderItems.stream().collect(Collectors.toMap(OrderItem::getId, v -> v));
        List<OrderPickUpDetail> pickUpDetails = new ArrayList<>(orderItems.size());
        context.setPickUpDetails(pickUpDetails);

        for (BalancePayItem payItem : payIn.getPayItems()) {
            if (payItem.getShippedNumber() > 0) {
                OrderItem orderItem = orderItemMap.get(payItem.getOrderItemId());
                Assert.notNull(orderItem, "通过Id【{}}】找不到订单行", payItem.getOrderItemId());

                // 一共买了多少，不可能为null
                int productNum = orderItem.getProductNum();
                // 已经付清了多少，在下单时设置为0，理论上也不会为null
                Integer shippedNum = orderItem.getShippedNum();
                Assert.notNull(shippedNum, "shippedNum不能为null");
                // 本次要付多少，前台传来的已经@Valid过，不会为null
                Integer willShipNum = payItem.getShippedNumber();
                // 本次付完后，一共付清了多少
                int willShippedNum = shippedNum + willShipNum;

                // 金额 = 总价 - 已付金额
                BigDecimal itemPay = orderItem.getTotalTaxPrice().subtract(orderItem.getPaidPrice());
                if (willShippedNum < productNum) {
                    // 还有剩余不付的，按比例计算
                    itemPay = PriceComputerUtil.divide(itemPay.multiply(new BigDecimal(willShipNum)), new BigDecimal(productNum - shippedNum));
                } else if (willShippedNum > productNum) {
                    throw new BytzBootException("产品【" + orderItem.getProductNumber() + "】不能超过可提货数量");
                }

                itemPay = PriceComputerUtil.saveScale(itemPay);

                OrderPickUpDetail pickUpDetail = new OrderPickUpDetail();
                pickUpDetails.add(pickUpDetail);
                pickUpDetail.setOrderItemId(orderItem.getId());
                pickUpDetail.setOrderId(orderItem.getOrderId());
                pickUpDetail.setProductId(orderItem.getProductId());
                pickUpDetail.setProductNumber(orderItem.getProductNumber());
                pickUpDetail.setProductDesc(orderItem.getProductDesc());
                pickUpDetail.setShippedNum(willShipNum);
                pickUpDetail.setPaidCreditNum(0);
                pickUpDetail.setPaidPrice(itemPay);

                totalPay = totalPay.add(itemPay);
            }
        }

        if (pickUpDetails.size() == 0) {
            throw new BytzBootException("没有可提的产品");
        }

        context.setPayAmount(totalPay);
    }

    @Override
    protected String getPayType() {
        return OrderPayConstants.PayType.BALANCE;
    }

    @Override
    protected String calculateCommodityMessage(BalancePayIn payIn, Order order, List<OrderItem> orderItems) {
        return "soldTo【" + order.getDemanderNumber() + "】" + "合同【" + order.getContractNumber() + "】尾款";
    }

    @Override
    protected void prepareNoOnlinePay(BalancePayPrepareContext context) {
        super.prepareNoOnlinePay(context);

        Order order = context.getOrder();
        OrderPay orderPay = context.getOrderPay();
        List<OrderItem> orderItems = context.getOrderItems();
        // 在计算支付价格（即calculatePayAmount方法）时生成的
        List<OrderPickUpDetail> pickUpDetails = context.getPickUpDetails();

        // 提交订单行，必须先提交这个，才能计算出订单是否已完成
        orderItemService.submitBalancePay(orderItems, pickUpDetails);

        // 提交订单
        orderService.submitBalancePay(order, orderPay.getTotalPayAmount(), orderItems);

        // 提交提货明细
        pickUpDetailService.directSubmitBalancePay(pickUpDetails,orderPay.getId());

        // 发送邮件通知om已提货
        orderEmailService.sendPickUpReminderEmail(order);
    }

    @Override
    protected void prepareHasOnlinePay(BalancePayPrepareContext context) {
        super.prepareHasOnlinePay(context);

        OrderPay orderPay = context.getOrderPay();
        // 在计算支付价格（即calculatePayAmount方法）时生成的
        List<OrderPickUpDetail> pickUpDetails = context.getPickUpDetails();

        // 提交提货明细
        pickUpDetailService.savePickupDetails(pickUpDetails,orderPay.getId());
    }

    @Override
    public void processOnlinePaySucceed(PayNotifyResult payNotifyResult, OrderPay orderPay, OrderPayDetail orderPayDetail) {
        List<OrderPickUpDetail> pickUpDetails = pickUpDetailService.getByOrderPayId(orderPay.getId());
        List<OrderItem> orderItems = orderItemService.getByOrderId(orderPay.getOrderId());
        Order order = orderService.getById(orderPay.getOrderId());

        // 订单行提交
        orderItemService.submitBalancePay(orderItems, pickUpDetails);

        // 订单提交
        orderService.submitBalancePay(order, orderPay.getTotalPayAmount(), orderItems);

        // 发送邮件通知om已提货
        orderEmailService.sendPickUpReminderEmail(order);

        // 提货明细提交
        pickUpDetailService.submitBalancePay(orderPay.getId());
    }

    @Override
    public void processOnlinePayFailed(PayNotifyResult payNotifyResult, OrderPay orderPay, OrderPayDetail orderPayDetail) {
        // 回滚尾款
        pickUpDetailService.rollbackBalancePay(orderPay.getId());
    }
}
